#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "syntaxtree.h"

extern Symtable symtable[0x3fff];
extern NODE *child[10];
Func curfunc;
int noNameStru = 0;

NODE *createNode(int type, int num, int lineno, union data_type *data)
{
    NODE *p = (NODE *)malloc(sizeof(NODE));
    p->type = type;     //标记种类
    p->lineno = lineno; //标记行号
    p->num = num;       //标记儿子个数
    if (type == _INT)
        (p->data).type_int = data->type_int;
    else if (type == _FLOAT)
        (p->data).type_float = data->type_float;
    else if (type == _TYPE)
    {
        if (!strcmp("int", (char *)data))
            (p->data).type_type = TYPE_INT;
        else if (!strcmp("float", (char *)data))
            (p->data).type_type = TYPE_FLOAT;
    }
    else if (type == _ID)
    {
        (p->data).type_id = (char *)malloc(strlen((char *)data));
        strcpy((p->data).type_id, (char *)data);
    }
    for (int i = 0; i < num; i++)
        if (child[i] != NULL)
            (p->child)[i] = child[i];
    return p;
}

void output(NODE *node, int level)
{
    if (node == NULL)
        return;
    for (int i = 0; i < level; i++)
        printf("    ");
    if (node->type == _INT)
        printf("%d: %d\n", node->type, (node->data).type_int);
    else if (node->type == _FLOAT)
        printf("%d: %f\n", node->type, (node->data).type_float);
    else if (node->type == _TYPE)
        printf("%d: %d\n", node->type, (node->data).type_type);
    else if (node->type == _ID)
        printf("%d: %s\n", node->type, (node->data).type_id);
    else
        printf("%d\n", node->type);
    for (int i = 0; i < node->num; i++)
        output((node->child)[i], level + 1);
}

void Program(NODE *node)
{
    if (node == NULL)
        return;
    ExtDeflist(node->child[0]);
}

void ExtDeflist(NODE *node)
{
    // empty
    if (node == NULL)
        return;
    // ExtDef ExtDeflist
    ExtDef(node->child[0]);
    ExtDeflist(node->child[1]);
}

void ExtDef(NODE *node)
{

    if (node == NULL)
        return;
    NODE *p;
    char *name;
    // Specifier SEMI
    if (node->num == 2)
        p = Specifier(node->child[0]);
    // Specifier ExtDeclist SEMI
    else if (node->child[2]->type == _SEMI)
    {
        p = Specifier(node->child[0]);
        if (p == NULL)
            return;
        ExtDeclist(node->child[1], p->data.sym_type);
    }
    // Specifier FunDec CompSt
    else
    {
        p = Specifier(node->child[0]);
        if (p == NULL)
            return;
        p = FunDec(node->child[1], p->data.sym_type, &name);
        Symbol s = CreateSymbolFunc(name, p->data.sym_func);
        if (!FindTable(s))
            InsertToTable(s);
        else
            myError("Error type 4 at Line ", node->lineno, name);
        curfunc = p->data.sym_func;
        Compst(node->child[2]);
    }
}

void ExtDeclist(NODE *node, Type type)
{
    if (node == NULL)
        return;
    if (node->num == 1)
        VarDec(node->child[0], type, NULL, NEW_VAR);
    else
    {
        if (VarDec(node->child[0], type, NULL, NEW_VAR))
            return;
        ExtDeclist(node->child[2], type);
    }
}

NODE *Specifier(NODE *node)
{
    if (node == NULL)
        return NULL;
    NODE *p = (NODE *)malloc(sizeof(NODE));
    NODE *q;
    // TYPE
    if (node->child[0]->type == _TYPE)
    {
        q = TTYPE(node->child[0]);
        p->type = S_TYPE;
        p->data.sym_type = CreateTypeBasic(q->data.type_type);
    }
    // StructSpecifier
    else
    {
        int num;
        char *name;
        q = StructSpecifier(node->child[0], &name, &num); //返回结构体
        //定义
        if (num == 5)
        {
            p->type = S_TYPE;
            p->data.sym_type = CreateTypeStructure(q->data.sym_structure);
            //匿名结构体，ID要求字母开头，此处使用数字开头，插入表中
            if (name == NULL)
            {
                sprintf(name, "%d", noNameStru);
                noNameStru++;
            }
            Symbol s = CreateSymbolStru(name, p->data.sym_type);
            if (!FindTable(s))
                InsertToTable(s);
            else
                return myError("Error type 16 at Line ", node->lineno, "Duplicated name");
        }
        //调用
        else
        {
            Symbol s = lookup(name);
            if (s == NULL)
                return myError("Error type 17 at Line ", node->lineno, name);
            else
            {
                p->type = S_TYPE;
                p->data.sym_type = s->u.structure;
            }
        }
    }
    return p;
}

NODE *StructSpecifier(NODE *node, char **name, int *num)
{
    if (node == NULL)
        return NULL;
    NODE *p = (NODE *)malloc(sizeof(NODE));
    NODE *q;
    *num = node->num;
    if (node->num == 5)
    {
        *name = OptTag(node->child[1]); //结构体类型的标签
        p->type = S_STRUCTURE;
        p->data.sym_structure = CreateStructure(CreateFieldHead(), *name); //创建头节点
        DefList(node->child[3], p->data.sym_structure->field, NEW_STRUCT); //连接域
    }
    else
        *name = Tag(node->child[1]);
    return p;
}

char *OptTag(NODE *node)
{
    if (node == NULL)
        return NULL;
    return TID(node->child[0]);
}

char *Tag(NODE *node)
{
    if (node == NULL)
        return NULL;
    return TID(node->child[0]);
}

Type VarDec(NODE *node, Type type, FieldList head, int kind)
{

    if (node == NULL)
        return NULL;
    if (node->num == 1)
    {
        char *name = TID(node->child[0]);
        Symbol s = CreateSymbolVar(name, type, kind);
        if (!FindTable(s))
            InsertToTable(s);
        else if (kind == NEW_STRUCT)
            return (Type)myError("Error type 15 at Line ", node->lineno, name);
        else
            return (Type)myError("Error type 3 at Line ", node->lineno, name);
        return type;
    }
    else
    {
        int size = TINT(node->child[2]);
        Array a = CreateArray(type, size);
        Type t = CreateTypeArray(a);
        Type tmp = VarDec(node->child[0], t, head, kind);
        return tmp; //多重数组递归调用
    }
}

NODE *FunDec(NODE *node, Type ret, char **name)
{
    if (node == NULL)
        return NULL;
    NODE *p = (NODE *)malloc(sizeof(NODE));
    *name = TID(node->child[0]);
    p->type = S_FUNC;
    Para head = CreateParaHead();
    if (node->num == 3)
    {
        Func f = CreateFunc(0, ret, head);
        p->data.sym_func = f;
    }
    else
    {
        int num = 0;
        VarList(node->child[2], head, &num); //连接在head后面,并计数
        Func f = CreateFunc(num, ret, head);
        p->data.sym_func = f;
    }
    return p;
}

void VarList(NODE *node, Para head, int *num)
{

    if (node == NULL)
        return;
    if (node->num == 1)
    {
        Type t = ParamDec(node->child[0]); //返回Type类型
        CreateParaNode(head, t);
        *num = *num + 1;
    }
    else
    {
        Type t = ParamDec(node->child[0]); //返回Type类型
        CreateParaNode(head, t);
        *num = *num + 1;
        VarList(node->child[2], head, num);
    }
}

Type ParamDec(NODE *node)
{
    if (node == NULL)
        return NULL;
    NODE *p = Specifier(node->child[0]);
    Type t = VarDec(node->child[1], p->data.sym_type, NULL, NEW_VAR);
    return t;
}

void Compst(NODE *node)
{
    if (node == NULL)
        return;
    DefList(node->child[1], NULL, NEW_VAR);
    StmtList(node->child[2]);
}

void StmtList(NODE *node)
{
    if (node == NULL)
        return;
    Stmt(node->child[0]);
    StmtList(node->child[1]);
}

void Stmt(NODE *node)
{
    NODE *p;
    if (node == NULL)
        return;
    switch (node->child[0]->type)
    {
    case _Exp:
        Exp(node->child[0]);
        return;
    case _RETURN:
        p = Exp(node->child[1]);
        if (p == NULL)
            return;
        else if (p->data.sym_type->u.basic != curfunc->ret->u.basic)
        {
            myError("Error type 8 at Line ", node->lineno, "Type mismatched for return");
            return;
        }
        return;
    case _WHILE:
        p = Exp(node->child[2]);
        if (p == NULL)
            return;
        else if (p->data.sym_type->kind != BASIC || p->data.sym_type->u.basic != TYPE_INT)
            myError("Error type 7 at Line ", node->lineno, "Type mismatched for WHILE");
        Stmt(node->child[4]);
    case _IF:
        p = Exp(node->child[2]);
        if (p == NULL)
            return;
        else if (p->data.sym_type->kind != BASIC || p->data.sym_type->u.basic != TYPE_INT)
            myError("Error type 7 at Line ", node->lineno, "Type mismatched for IF");
        Stmt(node->child[4]);
        if (node->num == 7)
            Stmt(node->child[6]);
    }
}

void DefList(NODE *node, FieldList head, int kind)
{

    if (node == NULL)
        return;
    Def(node->child[0], head, kind);
    DefList(node->child[1], head, kind);
}

void Def(NODE *node, FieldList head, int kind)
{
    if (node == NULL)
        return;
    NODE *p = Specifier(node->child[0]);
    if (p == NULL)
        return;
    Declist(node->child[1], p->data.sym_type, head, kind);
}

void Declist(NODE *node, Type type, FieldList head, int kind)
{
    if (node == NULL)
        return;
    if (node->num == 1)
        Dec(node->child[0], type, head, kind);
    else
    {
        Dec(node->child[0], type, head, kind);
        Declist(node->child[2], type, head, kind);
    }
}

void Dec(NODE *node, Type type, FieldList head, int kind)
{

    if (node == NULL)
        return;
    NODE *p;
    if (node->num == 1)
        VarDec(node->child[0], type, head, kind);
    else if (kind == NEW_STRUCT)
        myError("Error type 15 at Line ", node->lineno, "Init in struct");
    else
    {
        Type t = VarDec(node->child[0], type, head, kind);
        if (t == NULL)
            return;
        p = Exp(node->child[2]);
        if (p->data.sym_type->kind != t->kind)
            myError("Error type 7 at Line ", node->lineno, "Type mismatched for operands");
    }
}

NODE *Exp(NODE *node)
{
    if (node == NULL)
        return NULL;
    switch (node->num)
    {
    case 1:
        return ExpOneNode(node);
    case 2:
        return ExpTwoNode(node);
    case 3:
        return ExpThreeNode(node);
    case 4:
        return ExpFourNode(node);
    }
}

NODE *ExpOneNode(NODE *node)
{
    char *name;
    int kind;
    NODE *p = (NODE *)malloc(sizeof(NODE));
    NODE *q, *k;
    switch (node->child[0]->type)
    {
    case _ID:
        name = TID(node->child[0]);
        Symbol s = lookup(name);
        if (s == NULL)
            return myError("Error type 1 at Line ", node->lineno, name);
        if (s->kind == VAR)
        {
            p->type = S_TYPE;
            p->data.sym_type = s->u.var;
        }
        else if (s->beStru)
            return myError("Error type 0 at Line ", node->lineno, NULL);
        return p;
    default:
        kind = node->child[0]->type == _INT ? TYPE_INT : TYPE_FLOAT;
        p->type = S_TYPE;
        p->data.sym_type = CreateTypeBasic(kind);
        return p;
    }
}

NODE *ExpTwoNode(NODE *node)
{
    char *name;
    NODE *p = (NODE *)malloc(sizeof(NODE));
    NODE *q;
    q = Exp(node->child[1]);
    if (q == NULL)
        return NULL;
    p->type = S_TYPE;
    if (node->child[0]->type == _NOT)
    {
        if (q->data.sym_type->u.basic == TYPE_INT)
            p->data.sym_type = CreateTypeBasic(TYPE_INT);
        else
            return myError("Error type 7 at Line ", node->lineno, "Type mismatched for operands");
    }
    else
    {
        if (q->data.sym_type->kind == BASIC)
            p->data.sym_type = CreateTypeBasic(q->data.sym_type->u.basic);
        else
            return myError("Error type 7 at Line ", node->lineno, "Type mismatched for operands");
    }
    return p;
}
NODE *ExpThreeNode(NODE *node)
{
    char *name;
    NODE *p = (NODE *)malloc(sizeof(NODE));
    NODE *q, *k;
    switch (node->child[1]->type)
    {
    case _ASSIGNOP:
        //是否具有左值检查
        if (!((node->child[0]->num == 1 && node->child[0]->child[0]->type == _ID) || (node->child[0]->num == 4 && node->child[0]->child[1]->type == _LB) || (node->child[0]->num == 3 && node->child[0]->child[1]->type == _DOT)))
            return myError("Error type 6 at Line ", node->lineno, "The left_hand side of an assignment must be a variable");
        q = Exp(node->child[0]);
        k = Exp(node->child[2]);
        if (q == NULL || k == NULL)
            return NULL;
        if (q->data.sym_type->kind != k->data.sym_type->kind || q->data.sym_type->kind != BASIC || q->data.sym_type->u.basic != k->data.sym_type->u.basic)
            return myError("Error type 5 at Line ", node->lineno, "Type mismatched for assignment");
        else
        {
            p->type = S_TYPE;
            p->data.sym_type = CreateTypeBasic(q->data.sym_type->u.basic);
        }
        return p;
    case _AND:
        q = Exp(node->child[0]);
        k = Exp(node->child[2]);
        if (q == NULL || k == NULL)
            return NULL;
        if (q->data.sym_type->kind != k->data.sym_type->kind || q->data.sym_type->kind != BASIC || q->data.sym_type->u.basic != k->data.sym_type->u.basic || q->data.sym_type->u.basic != TYPE_INT)
            return myError("Error type 7 at Line ", node->lineno, "Type mismatched for operands");
        else
        {
            p->type = S_TYPE;
            p->data.sym_type = CreateTypeBasic(q->data.sym_type->u.basic);
        }
        return p;
    case _OR:
        q = Exp(node->child[0]);
        k = Exp(node->child[2]);
        if (q == NULL || k == NULL)
            return NULL;
        if (q->data.sym_type->kind != k->data.sym_type->kind || q->data.sym_type->kind != BASIC || q->data.sym_type->u.basic != k->data.sym_type->u.basic || q->data.sym_type->u.basic != TYPE_INT)
            return myError("Error type 7 at Line ", node->lineno, "Type mismatched for operands");
        else
        {
            p->type = S_TYPE;
            p->data.sym_type = CreateTypeBasic(q->data.sym_type->u.basic);
        }
        return p;
    case _RELOP:
        q = Exp(node->child[0]);
        k = Exp(node->child[2]);
        if (q == NULL || k == NULL)
            return NULL;
        if (q->data.sym_type->kind != k->data.sym_type->kind || q->data.sym_type->kind != BASIC || q->data.sym_type->u.basic != k->data.sym_type->u.basic || q->data.sym_type->u.basic != TYPE_INT)
            return myError("Error type 7 at Line ", node->lineno, "Type mismatched for operands");
        else
        {
            p->type = S_TYPE;
            p->data.sym_type = CreateTypeBasic(q->data.sym_type->u.basic);
        }
        return p;
    case _PLUS:
        q = Exp(node->child[0]);
        k = Exp(node->child[2]);
        if (q == NULL || k == NULL)
            return NULL;
        if (q->data.sym_type->kind != k->data.sym_type->kind || q->data.sym_type->kind != BASIC || q->data.sym_type->u.basic != k->data.sym_type->u.basic)
            return myError("Error type 7 at Line ", node->lineno, "Type mismatched for operands");
        else
        {
            p->type = S_TYPE;
            p->data.sym_type = CreateTypeBasic(q->data.sym_type->u.basic);
        }
        return p;
    case _MINUS:
        q = Exp(node->child[0]);
        k = Exp(node->child[2]);
        if (q == NULL || k == NULL)
            return NULL;
        if (q->data.sym_type->kind != k->data.sym_type->kind || q->data.sym_type->kind != BASIC || q->data.sym_type->u.basic != k->data.sym_type->u.basic)
            return myError("Error type 7 at Line ", node->lineno, "Type mismatched for operands");
        else
        {
            p->type = S_TYPE;
            p->data.sym_type = CreateTypeBasic(q->data.sym_type->u.basic);
        }
        return p;
    case _STAR:
        q = Exp(node->child[0]);
        k = Exp(node->child[2]);
        if (q == NULL || k == NULL)
            return NULL;
        if (q->data.sym_type->kind != k->data.sym_type->kind || q->data.sym_type->kind != BASIC || q->data.sym_type->u.basic != k->data.sym_type->u.basic)
            return myError("Error type 7 at Line ", node->lineno, "Type mismatched for operands");
        else
        {
            p->type = S_TYPE;
            p->data.sym_type = CreateTypeBasic(q->data.sym_type->u.basic);
        }
        return p;
    case _DIV:
        q = Exp(node->child[0]);
        k = Exp(node->child[2]);
        if (q == NULL || k == NULL)
            return NULL;
        if (q->data.sym_type->kind != k->data.sym_type->kind || q->data.sym_type->kind != BASIC || q->data.sym_type->u.basic != k->data.sym_type->u.basic)
            return myError("Error type 7 at Line ", node->lineno, "Type mismatched for operands");
        else
        {
            p->type = S_TYPE;
            p->data.sym_type = CreateTypeBasic(q->data.sym_type->u.basic);
        }
        return p;
    case _Exp:
        return Exp(node->child[1]);
    case _LP: //函数
        name = TID(node->child[0]);
        Symbol s = lookup(name);
        if (s == NULL)
            return myError("Error type 2 at Line ", node->lineno, name);
        else if (s->kind != FUNC)
            return myError("Error type 11 at Line ", node->lineno, name);
        else if (s->u.func->paranum != 0)
            return myError("Error type 9 at Line ", node->lineno, "error func paranum");
        p->type = S_TYPE;
        p->data.sym_type = s->u.func->ret;
        return p;
    case _DOT:
        q = Exp(node->child[0]);
        if (q == NULL)
            return NULL;
        else if (q->data.sym_type->kind != STRUCTURE)
            return myError("Error type 13 at Line ", node->lineno, "Illegal use of \".\"");
        else
        {
            FieldList head, fl;
            head = q->data.sym_type->u.structure->field->tail;
            name = TID(node->child[2]);
            while (head != NULL)
            {
                if (strcmp(head->name, name))
                    head = head->tail;
                else
                {
                    p->type = S_TYPE;
                    p->data.sym_type = head->type;
                    return p;
                }
            }
            return myError("Error type 14 at Line ", node->lineno, name);
        }
    }
}
NODE *ExpFourNode(NODE *node)
{
    char *name;
    NODE *p = (NODE *)malloc(sizeof(NODE));
    NODE *q;
    if (node->child[0]->type == _ID)
    {
        name = TID(node->child[0]);
        Symbol s = lookup(name);
        if (s == NULL)
            return myError("Error type 2 at Line ", node->lineno, name);
        else if (s->kind != FUNC)
            return myError("Error type 11 at Line ", node->lineno, name);
        //比对参数列表,返回空表示中间有错误，否则返回返回值的类型
        if (Args(node->child[2], s->u.func->para, s->u.func->paranum))
            return NULL;
        else
        {
            p->type = S_TYPE;
            p->data.sym_type = s->u.func->ret;
            return p;
        }
    }
    else
    {
        q = Exp(node->child[2]);
        if (q == NULL)
            return NULL;
        if (q->data.sym_type->kind != BASIC || q->data.sym_type->u.basic != TYPE_INT)
            return myError("Error type 12 at Line ", node->lineno, "not a integer");
        else
        {
            q = Exp(node->child[0]);
            if (q == NULL)
                return NULL;
            if (q->data.sym_type->kind != ARRAY)
                return myError("Error type 10 at Line ", node->lineno, "not an array");
            Array a = q->data.sym_type->u.array;
            p->type = S_TYPE;
            p->data.sym_type = a->elem;
            return p;
        }
    }
}

NODE *Args(NODE *node, Para para, int paranum)
{
    NODE *q;
    Para k = para->tail;
    if (node == NULL)
        return NULL;
    if (node->num == 1)
    {
        if (paranum != 1)
            return myError("Error type 9 at Line ", node->lineno, "error func paranum");
        q = Exp(node->child[0]);
        if (q == NULL)
            return NULL;
        if (k->type->kind != q->data.sym_type->kind)
            return myError("Error type 9 at Line ", node->lineno, "error para type");
        return q;
    }
    else
    {
        q = Exp(node->child[0]);
        if (q == NULL)
            return NULL;
        if (k->type->kind != q->data.sym_type->kind)
            return myError("Error type 9 at Line ", node->lineno, "error para type");
        return Args(node->child[2], k, paranum - 1);
    }
}

char *TID(NODE *node)
{
    return node->data.type_id;
}

float TFLOAT(NODE *node)
{
    return node->data.type_float;
}

int TINT(NODE *node)
{
    return node->data.type_int;
}

NODE *TTYPE(NODE *node)
{
    return node;
}

NODE *myError(const char *msg, int lineno, const char *name)
{
    if (name == NULL)
        printf("%s%d\n", msg, lineno);
    else
        printf("%s%d : %s\n", msg, lineno, name);
    return NULL;
}
